#include <MultiplexD_SignalHandlerWorker/Worker.h>

#include <unistd.h>
#include <signal.h>

#include <Ape/ENotImplemented.h>
#include <Ape/ENullPointer.h>
#include <Ape/EFloatingPoint.h>

#include <MultiplexD/DaemonInstance.h>
#include <MultiplexD/WorkerModel/MultiplexLetter.h>
#include <MultiplexD/DaemonAPI/ShutdownRequest.h>
#include <MultiplexD/Logging/Logger.h>

using namespace Ape::EventModel;

static Event<EventArgs> s_Dispatch;

static void signal_dispatcher (int sig) {
	if (sig == SIGSEGV) {
		Ape::ENullPointer eNullPtr (L"Access violation");
		throw eNullPtr;
	}
	if (sig == SIGFPE) {
		Ape::EFloatingPoint eFPE (L"Floating point error");
		eFPE._Dump (true);
		throw eFPE;
	}
	
	EventArgs ea (NULL, 1);
	ea.setArg (0, new Ape::UInt (sig), true);
	s_Dispatch (ea);
}

static void install_sighandlers() {
	DEBUG (L"Installing signal handlers...")
	static bool m_Installed = false;
	if (m_Installed)
		return;
	m_Installed = true;
	signal (SIGSEGV, signal_dispatcher);
	signal (SIGFPE, signal_dispatcher);
	
	signal (SIGINT, signal_dispatcher);
	signal (SIGQUIT, signal_dispatcher);
	signal (SIGTERM, signal_dispatcher);
	signal (SIGHUP, signal_dispatcher);
	signal (SIGUSR1, signal_dispatcher);
	signal (SIGUSR2, signal_dispatcher);
}

namespace MultiplexD {
	namespace SignalHandlerWorker {
		Worker::Worker() {
			DEBUG (L"Instantiating SignalHandlerWorker");
			DEBUG (L"Subscribing to the POSIX-signals");
			
			install_sighandlers();
			// subscribe for dispatcher
			s_Dispatch += Delegate (Worker, this, OnSignal);
		}
		Worker::~Worker() {
			DEBUG (L"Worker::~Worker()");
		}
		
		void Worker::OnSignal (Ape::EventModel::EventArgs& ea) {
		
			WorkerModel::MultiplexLetter letter;
			SignalHandlerData* data = new SignalHandlerData;
			data->SigNum = ea.A<Ape::UInt> (0);
			letter.LetterType = ltSignalCaught;
			letter.Data = data;
			Message (letter);
		}
		
		void Worker::ProcessMessage (const MultiplexD::WorkerModel::MultiplexLetter& letter) {
			switch (letter.LetterType) {
				case ltSignalCaught: {
						int sigNum = letter.GetData<SignalHandlerData>()->SigNum;
						DEBUG (L"Signal caught: " + Ape::UInt (sigNum).ToString() );
						switch (sigNum) {
							case SIGINT:
							case SIGQUIT:
							case SIGTERM: {
									WorkerModel::MultiplexLetter letter;
									letter.LetterType = WorkerModel::ltShutdown;
									DaemonAPI::ShutdownData* data = new DaemonAPI::ShutdownData;
									letter.Data = data;
									data->Reason = L"Signal caught: " + Ape::UInt (sigNum).ToString();
									DaemonInstance::Get()->MailBox().Send (letter);
									break;
								}
							case SIGHUP: {
									Ape::ENotImplemented eNotImpl(L"Hot reload is not implemented yet");
									//printf("-> %i\n", eNotImpl.__SizeOf());
									throw eNotImpl;
									break;
								}
							case SIGUSR1: {
									Ape::Object* o = NULL;
									o->_Dump();
								}
							case SIGUSR2: {
									int i = 0;
									float f = i / 0;
									printf ("%f\n", f); // ok. i know that won't be executed, but that'll shut up pedantic compiler
								}
						}
						break;
					}
			}
		}
	}
}

extern "C" Ape::Object* APE_new__MultiplexD__SignalHandlerWorker__Worker() {
	return new MultiplexD::SignalHandlerWorker::Worker;
}
